Compare-and-swap

Un article de Wikipédia, l'encyclopédie libre.

Compare-and-swap (CAS) est une instruction atomique utilisée dans les systèmes multiprocesseurs ou multi-cœurs utilisant une mémoire partagée. Elle compare la valeur stockée à une adresse mémoire donnée à l'un de ses arguments et, en cas d'égalité, écrit une nouvelle valeur à cette adresse. Selon les implémentations, elle signale si l'écriture a réussi soit en renvoyant une valeur booléenne, soit en renvoyant la valeur lue en mémoire.

L'instruction CAS simple ne présente presque aucun problème au niveau de la synchronisation de l'adresse mémoire auquel elle pointe, sauf dans un cas précis décrit comme le problème ABA (en).

Architectures supportées[modifier | modifier le code]

Cette opération de synchronisation est supportée par plusieurs architectures contemporaines, notamment sur Intel, AMD, et Oracle. Sur les architectures de Intel et AMD, cette instruction est appelée CMPXCHG, tandis que sur Oracle SPARC systems, elle est appelée CAS[1].

Leur fonctionnement reste globalement similaire. Contrairement à l'opération abstraite, l'instruction processeur prend 3 arguments : une adresse mémoire a, une valeur attendue e, et une valeur de mise à jour v, et retourne une valeur booléenne. Si la valeur contenue à l'adresse mémoire a contient la valeur attendue e, écrire la nouvelle valeur v à cette adresse et retourner vrai, sinon laisser la mémoire intacte et retourner faux.

Processeurs Intel[modifier | modifier le code]

La première instruction de type CAS est apparue en premier en 1989 sur le processeur Intel 80486.

Sur les processeurs Intel, il existe deux instructions similaires qui implémentent l'instruction CAS : CMPXCHG (compare and exchange) et CMPXCHG8B (compare and exchange 8 bytes). L'instruction CMPXCHG requiert 3 opérandes : une opérande de source dans un registre, une autre opérande de source dans le registre EAX et enfin une opérande de destination. Si les valeurs contenues dans l'opérande de destination et dans le registre EAX sont égales, alors l'opérande de destination est remplacée par la valeur de la deuxième opérande de source (la valeur qui ne se trouve pas dans le registre EAX). Sinon, la valeur contenue dans l'opérande de destination est chargée dans le registre EAX[2].

Cette instruction est utilisée pour tester et modifier des sémaphores. Si elle teste qu'un sémaphore est libre, alors elle le marquera comme étant alloué. Sinon elle renverra l'ID de son propriétaire. Elle peut être utilisée tout aussi bien en architecture monocœur qu'en multicœurs. Dans ce dernier cas, un préfixe LOCK peut être ajouté devant l'instruction pour la forcer à être atomique.

Exemple d'utilisation[modifier | modifier le code]

Voici un exemple d'utilisation tiré du noyau de Linux, la fonction rtc_cmos_read() , désassemblée, utilise l'instruction suivante[3],[4] :

 lock cmpxchg    %edx, cmos_lock

On peut la lire de la façon suivante :

  • prefix : lock
  • opcode: cmpxchg
  • source-operand: %edx
  • destination-operand: cmos_lock

Variantes[modifier | modifier le code]

CMPXCHG8B fonctionne de manière similaire mais avec des valeurs 64-bit au lieu de valeurs 32-bit, elle peut également être accompagné ou non du préfixe LOCK pour la forcer à agir de manière atomique. Elle prend également 3 opérandes : une valeur 64-bit dans EDX:EAX, une valeur 64-bit dans ECX:EBX, et une opérande de destination en mémoire (dont la valeur n'est pas précisée). L'instruction compare la valeur contenue dans EDX:EAX avec la valeur de l'opérande de destination. Si elles sont égales, la valeur des registres ECX:EBX est enregistrée dans l'opérande de destination, sinon la destination est chargée dans les registres EDX:EAX.

Il existe également une instruction uniquement disponible pour les architectures 64-bit, appelée CMPXCHG16B, qui est une extension de l'instruction CMPXCHG8B et opère sur des données de 128-bit.

Problème du Consensus[modifier | modifier le code]

L'instruction Compare-and-Swap fait l'objet d'un théorème particulier en ce qui concerne le problème du consensus[5],[6].

Théorème — Un registre qui fournit à la fois les méthodes compareAndSwap() et Get() possède un numéro de consensus infini.

Problème ABA[modifier | modifier le code]

Le problème ABA (en) résulte d'un défaut lié au fonctionnement même de l'instruction CAS. Elle apparait communément dans la situation suivante :

  1. Une application lit une valeur a d'une adresse mémoire donnée, et calcule une nouvelle valeur c pour cette adresse.
  2. Elle essaye de sauvegarder c, mais seulement si la valeur a à l'adresse mémoire n'a pas été changée depuis qu'elle a été lue.
  3. Pendant ce temps-là, un autre thread a réécrit l'adresse mémoire de a avec une valeur b, puis plus tard réécrit a à cet emplacement-là.

L'opération CAS va remplacer a avec c, mais peut-être que l'application n'aura pas agit comme on s'y attendait. Par exemple, si l'adresse a mémorise un pointeur, la nouvelle valeur a sera peut-être l'adresse d'un objet recyclé.

Notes et références[modifier | modifier le code]

  1. (en) Maurice Herlihy, Nir Shavit, Victor Luchangco et Michael Spear, The art of multiprocessor programming, Morgan Kaufmann, 2e éd. (ISBN 978-0-12-415950-1), p. 529
  2. (en) Intel, Intel® 64 and IA-32 Architectures - Software Developer’s Manual - Combined Volumes:1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D and 4, Intel Corporation, , 5106 p. (lire en ligne), Vol.1 7-4 (pdf: p178), 7-5 (pdf: p179) ; Vol.2A 3-592 (pdf: p1186)
  3. (en) « Intel’s ‘cmpxchg’instruction » [PDF], sur cs.ucdavis.edu (consulté le )
  4. (en) « Linux kernel x86 - rtc.c » [html] (Code source du noyau Linux v5.12 en C), sur elixir.bootlin.com (consulté le )
  5. (en) Maurice Herlihy, Nir Shavit, Victor Luchangco et Michael Spear, The art of multiprocessor programming, Morgan Kaufmann, 2e éd. (ISBN 978-0-12-415950-1), p. 119
  6. (en) Michael J. Fischer, Nancy A. Lynch et Michael S. Paterson, « Impossibility of Distributed Consensus with One Faulty Process », Journal of the ACM, Association for Computing Machinery, vol. 32, no 2,‎ , p. 374–382 (ISSN 0004-5411, DOI 10.1145/3149.214121, lire en ligne, consulté le )